#ifndef CMDCOMBINER_H
#define CMDCOMBINER_H

#include <QObject>

class CmdCombiner : public QObject
{
    Q_OBJECT
public:
    explicit CmdCombiner(QObject *parent = 0);

    const static quint8 MAX_CMD_LEN=255;
    const static quint16 MAX_CMD_GROUP_LEN=1024;

protected:
    quint8 m_Cmds[MAX_CMD_GROUP_LEN];
    quint8 m_CmdCount;
    quint16 m_CurrentPointer;

public:
    /*!
     * \brief 获取一组命令的第nCmdIndex条命令的起始字节偏移量（包含命令长度的字节索引）。
     * \param Cmds 命令组合，最长不应超过MAX_CMD_GROUP_LEN。
     * \param nCmdIndex 命令序号，从0开始。
     * \return 起始字节偏移量（包含命令长度的字节索引），负数表示失败。
     */
    static int getStartIndexOfCmd(const quint8 *Cmds, quint8 nCmdIndex)
    {
        int nCurrentPointer=0;
        for (quint8 nCurrentCmdIndex=0; nCurrentCmdIndex<nCmdIndex; nCurrentCmdIndex++)
        {
            int nCurrentCmdLen=Cmds[nCurrentPointer];
            if (0==nCurrentCmdLen) return -1;
            nCurrentPointer+=(nCurrentCmdLen+1);
            if (nCurrentPointer>=MAX_CMD_GROUP_LEN-2) return -1;

        }
        return nCurrentPointer;
    }

    /*!
     * \brief 返回Icc执行结果的状态字。
     * \param Cmd 命令，首字节为命令长度。
     * \return SW，如果解析命令错误返回-1。
     */
    static int getIccSw(const quint8 *Cmd)
    {
        int nCmdLen=Cmd[0];
        if (nCmdLen<2) return -1;
        return Cmd[nCmdLen-2+1]*256+Cmd[nCmdLen-2+2];
    }

public:
    /*!
     * \brief 解析命令组合。
     * \param Cmds 命令组合。
     * \param nCmdCount 命令数量。
     * \return true表示解析成功。
     */
    bool parseCmds(const quint8 *Cmds, quint8 nCmdCount)
    {
        if (0==nCmdCount) return false;
        int nStartIndexOfTheLastCmd=getStartIndexOfCmd(Cmds, nCmdCount-1);
        if (nStartIndexOfTheLastCmd<0) return false;
        if (nStartIndexOfTheLastCmd>MAX_CMD_GROUP_LEN-2) return false;
        quint16 nCmdsLen=nStartIndexOfTheLastCmd+Cmds[nStartIndexOfTheLastCmd]+1;
        if (nCmdsLen>MAX_CMD_GROUP_LEN) return false;
        memcpy(m_Cmds, Cmds, nCmdsLen);
        m_CmdCount=nCmdCount;
        m_CurrentPointer=nCmdsLen;
        return true;
    }

    bool parseCmds(const QByteArray &baCmds, quint8 nCmdCount)
    {
        quint8 Cmds[MAX_CMD_GROUP_LEN];
        memset(Cmds, 0, sizeof Cmds);
        memcpy(Cmds, baCmds.constData(), qMin(baCmds.length(), (int)sizeof(Cmds)));
        return parseCmds(Cmds, nCmdCount);
    }

public:
    /*!
     * \brief 获取组合好的命令，注意返回的字符指针不应被修改。
     * \return 获取组合好的命令。
     */
    inline quint8 *getCombinedCmds()
    {
        return m_Cmds;
    }

    /*!
     * \brief 获取第nCmdIndex条指令的指针。
     * \param nCmdIndex 命令序号，从0开始。
     * \return 如果出现错误返回NULL。
     */
    quint8 *getCmdPointer(quint8 nCmdIndex)
    {
       int index=getStartIndexOfCmd(m_Cmds, nCmdIndex);
       if (index<0) return NULL;
       return m_Cmds+index;
    }

    /*!
     * \brief 获取命令条数。
     * \return
     */
    inline quint8 getCmdCount() const
    {
        return m_CmdCount;
    }

    /*!
     * \brief 开始命令组合。
     * \param Cmd 命令，不包含命令长度。
     * \param nCmdLen 命令长度
     * \return true表示成功。
     */
    bool initialCmd(const quint8 *Cmd, quint8 nCmdLen)
    {
        quint8 OldCmdCount=m_CmdCount;
        quint16 OldCurrentPointer=m_CurrentPointer;
        m_CmdCount=0;
        m_CurrentPointer=0;
        bool bRlt=appendCmd(Cmd, nCmdLen);
        if (!bRlt)
        {
            m_CmdCount=OldCmdCount;
            m_CurrentPointer=OldCurrentPointer;
        }
        return bRlt;
    }

    /*!
     * \brief 附加新的命令。
     * \param Cmd 命令，不包含命令长度。
     * \param nCmdLen 命令长度
     * \return true表示成功。
     */
    bool appendCmd(const quint8 *Cmd, quint8 nCmdLen);

    /*!
     * \brief 开始命令组合。
     * \param Cmd 命令，首字节为命令长度。
     * \return true表示成功。
     */
    bool initialCmd(const quint8 *Cmd)
    {
        return initialCmd(Cmd+1, Cmd[0]);
    }

    /*!
     * \brief 附加新的命令。
     * \param Cmd 命令，首字节为命令长度。
     * \return true表示成功。
     */
    bool appendCmd(const quint8 *Cmd)
    {
        return appendCmd(Cmd+1, Cmd[0]);
    }

    /*!
     * \brief 开始命令组合。
     * \param Cmd 命令，不包含命令长度，命令长度根据字符串长度判断。
     * \return true表示成功。
     */
    bool initialCmd(const QString Cmd);

    /*!
     * \brief 附加新的命令。
     * \param Cmd 命令，不包含命令长度，命令长度根据字符串长度判断。
     * \return true表示成功。
     */
    bool appendCmd(const QString Cmd);

    /*!
     * \brief 将命令组合转化为字符串，命令包含在<>内，以便于日志记录。
     * \return 字符串
     */
    QString toString();

public:
    /*!
     * \brief 检查各条命令返回结果的状态字，有一条与期待值不符合即返回false。
     * \return
     */
    bool verifySW(QString &sErrorMsg, const quint16 expectedSW=0x9000) const;

};

#endif // CMDCOMBINER_H
